package com.mloeppky.setgame.client;


import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Widget;

public class SetCard extends FocusPanel {
	
	/**
	 * The color trait of a card from the game of Set.
	 */
	public enum Color {
		Green, Purple, Red
	}
	
	/**
	 * The shape trait of a card from the game of Set.
	 */
	public enum Shape {
		Diamond, Squiggle, Oval
	}
	
	/**
	 * The fill trait of a card from the game of Set.
	 */
	public enum Fill {
		Striped, Solid, Outline
	}
	
	private Color color;
	private Shape shape;
	private Fill fill;
	private int qty;
	
	/**
	 * Where the card is rendered
	 */
	private FlexTable table;
	
	/**
	 * Generates a new {@link SetCard} with the given traits
	 * @param qty
	 * @param color
	 * @param shape
	 * @param fill
	 */
	public SetCard(int qty, Color color, Shape shape, Fill fill) {
		this.qty = qty;
		this.color = color;
		this.shape = shape;
		this.fill = fill;
		draw();
	}
	
	/**
	 * @return A new {@link SetCard} with the random traits
	 */
	public static SetCard newRandomSetCard() {
		return new SetCard(
				randomNumber1To3(),
				getRandomTrait(Color.class),
				getRandomTrait(Shape.class),
				getRandomTrait(Fill.class));
	}
	
	///////////////////////////////
	// Java Bean Getters/Setters //
	///////////////////////////////
	
	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		this.color = color;
	}

	public Shape getShape() {
		return shape;
	}

	public void setShape(Shape shape) {
		this.shape = shape;
	}

	public Fill getFill() {
		return fill;
	}

	public void setFill(Fill fill) {
		this.fill = fill;
	}

	public int getQuantity() {
		return qty;
	}

	public void setQuantity(int quantity) {
		this.qty = quantity;
	}
	
	/**
	 * @return A random number from 1 to 3
	 */
	private static int randomNumber1To3() {
		return (int)(Math.random() * 3) + 1;
	}
	
	/**
	 * Gets a random trait of the given enum
	 * @param e An enum class
	 * @return A random constant of the given enum
	 * @throws IllegalArgumentException If the given e isn't an enum
	 */
	public static <T extends Enum<T>> T getRandomTrait(Class<T> e) {
		T[] traits = e.getEnumConstants();
		if (traits != null) {
			return traits[(int) (Math.random() * traits.length)];
		} else {
			throw new IllegalArgumentException(e + " should be an enum with exactly 3 constants");
		}
	}
	
	/**
	 * Renders the card.
	 */
	private void draw() {
		table = new FlexTable();
		table.setStyleName("card");
		
		//Add qty copies of the image to the table
		for (int i = 0; i < qty; i++) {
			table.setWidget(0, i, new Image("images/" + 
					fill.name() + 
					color.name() + 
					shape.name() + ".png"));
		}
		
		super.add(table);
	}
	
	/**
	 * Sets the card to either the selected or not selected css style.
	 * @param selected True sets the style to the selected css style. False
	 * set the style to the non selected css style.
	 */
	public void setSelected(boolean selected) {
		if (selected) {
			table.setStyleName("cardSelected");
		} else {
			table.setStyleName("card");
		}
	}
	
	/**
	 * 3 solid purple diamonds would be represented as
	 * <p>
	 * [3, Solid, Purple, Diamond]
	 */
	@Override
	public String toString() {
		Joiner joiner = Joiner.on(", ");
		return "[" + joiner.join(qty, fill.name(), color.name(), shape.name()) + "]";
	}
	
	
	@Override
	public boolean equals(Object o) {
		if (o instanceof SetCard) {
			SetCard other = (SetCard) o;
			return Objects.equal(other.qty, this.qty)
				&& Objects.equal(other.fill, this.fill)
				&& Objects.equal(other.color, this.color)
				&& Objects.equal(other.shape, this.shape);
		} else {
			return false;
		}
	}
	
	/**
	 * Makes adding and getting from as {@link HashSet} much faster.
	 */
	@Override
	public int hashCode() {
		return Objects.hashCode(qty, fill, color, shape);
	}
	
	/**
	 * NO WIDGET WILL BE ADDED TO THE PANEL!!! The card adds itself to the panel.
	 */
	@Override
	public void add(Widget widget) {
		//Do nothing
	}

}
